package warden;

import java.util.Hashtable;

import log.Logger;
import log.NullLogger;

import philosoph.Philosoph;

public class SimpleEatAmountWarden<T extends Philosoph> implements EatAmountWarden<T> {

	private class Value {
		private int value = 0;
		synchronized public void increment() {value++;}
		public int getValue() {return value;}
	}

	private int stallTime;
	private int difference;
	private Logger logger;

	private int average = 0;
	private Hashtable<T, Value> philosoph;

	public SimpleEatAmountWarden(int stallTime, int difference, T... philosophs) {
		this(new NullLogger(), stallTime, difference, philosophs);
	}

	public SimpleEatAmountWarden(Logger logger, int stallTime, int difference, T... philosophs) {
		this.stallTime = stallTime;
		this.difference = difference;
		this.philosoph = new Hashtable<T, Value>(philosophs.length << 1);
		for (T t : philosophs) {
			this.philosoph.put(t, new Value());
		}
		this.logger = logger;
	}

	@Override
	public void blockPhilosoph(T philosoph) throws InterruptedException {
		int philAverage = this.philosoph.get(philosoph).getValue();
		if (philAverage > this.difference + this.average) {
			this.logger.log(-1, "Philosoph Nr. " + String.format("%4d", philosoph.hashCode()) + " has been banned from the table.");
			Thread.sleep(this.stallTime);
		}
	}

	@Override
	public void incrementPhilosoph(T philosoph) {
		this.philosoph.get(philosoph).increment();
		this.recalculate();
	}

	private void recalculate() {
		int sum = 0;
		int div = 0;
		for (Value v : this.philosoph.values()) {
			sum += v.getValue();
			div++;
		}
		if (div == 0) return;
		int result = sum / div;
		if (result > this.average) this.setAverage(result);
	}

	synchronized private void setAverage(int i) {
		this.average = i;
	}

}
